/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/

//promise 的实现
//promise.all 的实现
//promise.resove() 方法的实现
//promise.finally 的实现
//promise.catch  最终抛出的异常

//什么是promise
/*

1.promise 就是一个类 在执行这个类的时候  需要传递一个执行器会立即执行
2.promise 中有三个状态 分别为 成功 fulfilled 失败  rejected  等待 padding  padding -> fulfilled  padding -> rejected
  一旦状态确定就不可更改
3. resove 和 rejected 函数是用来更改状态的  resove-> fulfilled reject-> rejected
4. then 方法内部做的事情就判断状态 如果状态是成功 调用成功的回调函数  如果状态是失败 调用失败的回调函数
5. then 成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 吊饰失败后的原因
6. 解决异步问题
7. then方法对此调用添加多个处理函数
8. then方法的链式调用
9. 不能返回自对象  会循环调用  如果这样调用应该报一个错误细腻些
10.then的参数是可选参数  可选参数的处理
11.promise.all  方法 是用来处理异步并发的问题  什么叫做 异步并发 呢？ ==  待查询  按照异步代码调用的顺序  得到异步代码执行的结果  接受一个数组
12.promise.resolve 将给定的值转成promise对象  返回值就是promise对象  也可以接受promise对象
13.finally 方法  无论当前的promise 对象的状态是失败的还是成功的  finally的回调函数始终都会被执行 第二个特点  在finally方法使用.then方法里能拿到结果值
14.catch 方法
*/
//定义常量的目的是为了 复用和代码有提示
//第一步的基本实现
//第二步 逐步实现
//第三步 添加一些异常处理
//第四步 添加一些静态方法
const PADDING = 'padding'   //等待
const FUFILLED = 'fufilled' //成功
const REJECTED = 'rejected' //失败
class MyPromise{
    constructor (executor){
        try {
            //立即执行函数
            executor(this.resove,this.reject)
        } catch (error) {
            this.reject(error)
        }
    }
    //状态
    status = PADDING
    //成功之后的值
    value = undefined
    //失败后的原因
    reason = undefined
    //成功回调
    successCallback = []
    //失败回调
    failCallback = []

    resove = value =>{
        //如果状态不是padding 就不能再修改状态了 组织程序向下执行
        if(this.status != PADDING) return
        //将状态更改为成功
        this.status = FUFILLED
        this.value = value
        // this.successCallback && this.successCallback(this.value)
        while(this.successCallback.length) this.successCallback.shift()() 
    }
    reject = reason =>{
        if(this.status != PADDING) return
        //将状态更改为失败
        this.status = REJECTED
        this.reason = reason
        // this.failCallback && this.failCallback(this.reason)
        while(this.failCallback.length) this.failCallback.shift()() 
    }
    then = (successCallback,failCallback) =>{
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason }
        let myPromise  = new MyPromise((resove,reject)=>{
            //立即执行器  会立即执行
            if(this.status == FUFILLED){
                setTimeout(() => {
                    try {
                        let x =  successCallback(this.value);
                        //1.判断x的值是普通值还是promise对象
                        //2.如果是promise对象 查看promise对象返回的结果
                        //3.再根据promise对象返回的结果，决定调用resolve 还是调用reject
                        resovePromise(myPromise,x,resove,reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            }
            else if(this.status == REJECTED){
                setTimeout(() => {
                    try {
                        let x =  failCallback(this.reason);
                        //1.判断x的值是普通值还是promise对象
                        //2.如果是promise对象 查看promise对象返回的结果
                        //3.再根据promise对象返回的结果，决定调用resolve 还是调用reject
                        resovePromise(myPromise,x,resove,reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            }else{
                this.successCallback.push(()=>{
                    setTimeout(() => {
                        try {
                            let x =  successCallback(this.value);
                            //1.判断x的值是普通值还是promise对象
                            //2.如果是promise对象 查看promise对象返回的结果
                            //3.再根据promise对象返回的结果，决定调用resolve 还是调用reject
                            resovePromise(myPromise,x,resove,reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                })
                this.failCallback.push(()=>{
                    setTimeout(() => {
                        try {
                            let x =  failCallback(this.reason);
                            //1.判断x的值是普通值还是promise对象
                            //2.如果是promise对象 查看promise对象返回的结果
                            //3.再根据promise对象返回的结果，决定调用resolve 还是调用reject
                            resovePromise(myPromise,x,resove,reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                }) 
            }
        })
        
        return myPromise
    }
    finally(callback){//处理异步的问题
       return this.then((value)=>{
          return MyPromise.resolve(callback()).then(() => value)
        },(reason)=>{
            return MyPromise.resolve(callback()).then(() =>{throw reason} )
        })
    }
    catch(failCallback){
        this.then(undefined,failCallback)
    }
    static all = (array)=>{//
        let result = []
        let index = 0//解决index的问题
        return new MyPromise((resove,reject)=>{
            function addData(key,value){
                result[key] = value
                index++
                if(index == array.length){
                    resove(result)//等待异步操作的结果
                }
            }
            for(let i=0;i<array.length;i++){//for循环没有执行异步操作
                let current = array[i];
                if(current instanceof MyPromise){
                    current.then(value => addData(i,value),reason => reject(reason))
                }else{
                    addData(i,current)
                }
            }
        })
    }
    static resolve = (value) => {
        if(value instanceof MyPromise) return value
        return new MyPromise((resove,reject)=>{
            resove(value)
        })
    }
};

function resovePromise(myPromise,x,resove,reject){
    if(myPromise === x ){
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if(x instanceof MyPromise){
        x.then(resove,reject)
    }else{
       resove(x) 
    }
}
module.exports = MyPromise